package com.cskaoyan.mall.search.service.impl;

import com.cskaoyan.mall.dto.ProductDto;
import com.cskaoyan.mall.search.consts.SearchRetCode;
import com.cskaoyan.mall.search.converter.ProductConverter;
import com.cskaoyan.mall.search.dto.SearchRequest;
import com.cskaoyan.mall.search.dto.SearchResponse;
import com.cskaoyan.mall.search.entity.ItemDocument;
import com.cskaoyan.mall.search.repository.ProductRepository;
import com.cskaoyan.mall.search.service.ProductSearchService;
import com.cskaoyan.mall.search.utils.ExceptionProcessorUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.HighlightQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: csmall-practice
 * @description:
 * @author: Lexis
 * @create: 2022-05-26 20:30
 **/
@Slf4j
@Service
public class ProductSearchServiceImpl implements ProductSearchService {

    @Autowired
    ProductRepository productRepository;

    @Autowired
    ProductConverter productConverter;

    @Autowired
    ElasticsearchRestTemplate restTemplate;

    @Override
    public SearchResponse search(SearchRequest request) {
        SearchResponse<ProductDto> response = new SearchResponse<>();
        try {
            request.requestCheck();
            String keyword = request.getKeyword();
            List<ItemDocument> itemDocuments = productRepository.matchSearch(keyword);
            List<ProductDto> productDtos = productConverter.items2Dto(itemDocuments);
            log.info("product+{}", productDtos);
            response.setData(productDtos);
            response.setCode(SearchRetCode.SUCCESS.getCode());
            response.setMsg(SearchRetCode.SUCCESS.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public SearchResponse fuzzySearch(SearchRequest request) {
        SearchResponse<ProductDto> response = new SearchResponse<>();

        try {
            request.requestCheck();

            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

            // 获取bool查询Builder
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            // 构造bool查询中queryString查询
            QueryStringQueryBuilder queryString = QueryBuilders.queryStringQuery(request.getKeyword()).field("title").field("sellPoint");
            boolQueryBuilder.must(queryString);

            // 构造bool查询中范围查询
            RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price");
            priceRange.gt(request.getPriceGt());
            priceRange.lte(request.getPriceLte());
            boolQueryBuilder.filter(priceRange);

            // 将bool查询添加到NaticeSearchQueryBuilder
            queryBuilder.withQuery(boolQueryBuilder);

            // 构造分页参数

            PageRequest pageRequest = null;
            if ("-1".equals(request.getSort())) {
                pageRequest = PageRequest.of(request.getCurrentPage() - 1, request.getPageSize(), Sort.by(Sort.Order.desc("price")));
            } else if ("1".equals(request.getSort())) {
                pageRequest = PageRequest.of(request.getCurrentPage() - 1, request.getPageSize(), Sort.by(Sort.Order.asc("price")));
            } else {
                pageRequest = PageRequest.of(request.getCurrentPage() - 1, request.getPageSize());
            }
            // 向NativeSearchQueryBuilder添加分页参数
            queryBuilder.withPageable(pageRequest);

            // 构造高亮参数
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title").preTags("<font color='red'>").postTags("</font>");
            highlightBuilder.field("sellPoint").preTags("<font color='red'>").postTags("</font>");
            // 向NativeSearchQueryBuilder添加高亮参数
            queryBuilder.withHighlightBuilder(highlightBuilder);

            // 使用ElasticsearchRestTemplate发起搜索请求
            SearchHits<ItemDocument> searchHits = restTemplate.search(queryBuilder.build(), ItemDocument.class);
            // 获取满足条件的总文档的数量
            long totalHits = searchHits.getTotalHits();
            // 获取包含所有命中文档
            List<SearchHit<ItemDocument>> hits = searchHits.getSearchHits();

            List<ProductDto> productDtos = new ArrayList<>();
            //  处理搜索到的结果集
            hits.forEach(hit -> {
                log.info("hit+{}", hit);
                ItemDocument content = hit.getContent();
                // 获取高亮字段
                List<String> title = hit.getHighlightField("title");
                if (!CollectionUtils.isEmpty(title)) {
                    content.setTitle(title.get(0));
                }
                // sellPoint前端不会显示样式
                // List<String> sellPoint = hit.getHighlightField("sellPoint");
                // if (!CollectionUtils.isEmpty(sellPoint)) {
                //     content.setSellPoint(sellPoint.get(0));
                // }
                ProductDto productDto = productConverter.item2Dto(content);
                productDtos.add(productDto);
            });
            response.setData(productDtos);
            response.setTotal(totalHits);
            response.setCode(SearchRetCode.SUCCESS.getCode());
            response.setMsg(SearchRetCode.SUCCESS.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
        //
        // try {
        //     request.requestCheck();
        //
        //     Sort sort = null;
        //     if ("DESC".equals(request.getSort())) {
        //         sort = Sort.by(Sort.Direction.DESC, "price");
        //     } else if ("ASC".equals(request.getSort())) {
        //         sort = Sort.by(Sort.Direction.ASC, "price");
        //     }
        //
        //
        //     PageRequest of = null;
        //
        //     // 分页参数
        //     if (sort != null) {
        //         of = PageRequest.of(request.getCurrentPage() - 1, request.getPageSize(), sort);
        //     } else {
        //         of = PageRequest.of(request.getCurrentPage() - 1, request.getPageSize());
        //     }
        //
        //
        //     // 这里的Page对象可以被看做是List
        //     Page<ItemDocument> pageResult = productRepository.testSearchPage(request.getKeyword(), request.getPriceGt(), request.getPriceLte(), of);
        //
        //     // log.info("resule+{}", pageResult.getContent().get(0));
        //
        //     List<ProductDto> productDtos = new ArrayList<>();
        //     // 如果需要返回可以在遍历的时候将其，放入一个List中返回
        //     pageResult.forEach(itemDocument -> {
        //         // 访问查询到的一条文档
        //         ProductDto productDto = productConverter.item2Dto(itemDocument);
        //         productDtos.add(productDto);
        //         // ...
        //     });
        //
        //     log.info("product+{}", productDtos);
        //     // 获取满足条件的总的文档数量
        //     long totalElements = pageResult.getTotalElements();
        //     response.setData(productDtos);
        //     response.setTotal(totalElements);
        //     response.setCode(SearchRetCode.SUCCESS.getCode());
        //     response.setMsg(SearchRetCode.SUCCESS.getMsg());
        // } catch (Exception e) {
        //     e.printStackTrace();
        //     ExceptionProcessorUtils.wrapperHandlerException(response, e);
        // }
        // return response;
    }
}
